/*
 * MIT License
 *
 * Copyright (c) 2020 wen.gu <454727014@qq.com>
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

 /***************************************************************************
 * Name: manifest_configure.cpp
 *
 * Purpose: manifest configure implementation
 *
 * Developer:
 *   wen.gu , 2020-05-25
 *
 * TODO:
 *
 ***************************************************************************/

 /******************************************************************************
 **    INCLUDES
 ******************************************************************************/
#include "ara/impl/manifest_configure.h"

#include <stdio.h>

//#include "ara/impl/impl_error_domain.h"

//#define LOG_TAG "plgm"
//#include "panda/core/log.h"

namespace ara
{
namespace impl
{
/******************************************************************************
 **    MACROS
 ******************************************************************************/
#define LOGE printf
#define LOGD printf
/******************************************************************************
 **    VARIABLE DEFINITIONS
 ******************************************************************************/



/******************************************************************************
 **    FUNCTION DEFINITIONS
 ******************************************************************************/
 class ManifestConfigure::impl
{
public:
    bool mIsLoaded = false;
    Value mCfgJson;
};


///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
ManifestConfigure::ManifestConfigure()
    :mImpl(new impl)
{
    /** todo something */
}

ManifestConfigure::~ManifestConfigure()
{
    /** todo something */
}


bool ManifestConfigure::Load(const ara::core::String& cfgFile)
{
    if (mImpl->mIsLoaded)
    {
        return true;
    }


    FILE* fp = fopen(cfgFile.c_str(), "rb");

    if (fp)
    {
        fseek(fp, 0, SEEK_END);
        uint32_t size = ftell(fp);
        fseek(fp, 0, SEEK_SET);
        uint8_t* cfgStr = new uint8_t[size + 1];
        int32_t retSize = fread(cfgStr, 1, size, fp);

        if (retSize > 0)
        {
            if (JsonParse((const char*)cfgStr, (const char*)cfgStr + retSize, mImpl->mCfgJson))
            {
                mImpl->mIsLoaded = true;
            }
        }

        delete[] cfgStr;
        fclose(fp);
    }
    else
    {
        LOGE("fopen configure file(%s) failed(%s)\n", cfgFile.c_str(), strerror(errno));
    }

    return mImpl->mIsLoaded;
}

bool ManifestConfigure::Unload()
{
    mImpl->mCfgJson.clear();
    mImpl->mIsLoaded = false;
    return true;
}

bool ManifestConfigure::Get(const String& key, String& val)
{
    Value& jval = mImpl->mCfgJson;
    if (jval.isMember(key))
    {
        Value& retVal = jval[key];

        if (retVal.isString())
        {
            val = retVal.asString();
            return true;
        }        
    }
    return false;
}

bool ManifestConfigure::Get(const String& key, int8_t& val)
{
    Value& jval = mImpl->mCfgJson;
    if (jval.isMember(key))
    {
        Value& retVal = jval[key];

        if (retVal.isInt())
        {
            val = retVal.asInt();
            return true;
        }
    }
    return false;
}
bool ManifestConfigure::Get(const String& key, int16_t& val)
{
    Value& jval = mImpl->mCfgJson;
    if (jval.isMember(key))
    {
        Value& retVal = jval[key];

        if (retVal.isInt())
        {
            val = retVal.asInt();
            return true;
        }
    }
    return false;
}

bool ManifestConfigure::Get(const String& key, int32_t& val)
{
    Value& jval = mImpl->mCfgJson;
    if (jval.isMember(key))
    {
        Value& retVal = jval[key];

        if (retVal.isInt())
        {
            val = retVal.asInt();
            return true;
        }
    }
    return false;
}
bool ManifestConfigure::Get(const String& key, int64_t& val)
{
    Value& jval = mImpl->mCfgJson;
    if (jval.isMember(key))
    {
        Value& retVal = jval[key];

        if (retVal.isInt64())
        {
            val = retVal.asInt64();
            return true;
        }
    }
    return false;
}
bool ManifestConfigure::Get(const String& key, uint8_t& val)
{
    Value& jval = mImpl->mCfgJson;
    if (jval.isMember(key))
    {
        Value& retVal = jval[key];

        if (retVal.isUInt())
        {
            val = retVal.asUInt();
            return true;
        }
    }
    return false;
}
bool ManifestConfigure::Get(const String& key, uint16_t& val)
{
    Value& jval = mImpl->mCfgJson;
    if (jval.isMember(key))
    {
        Value& retVal = jval[key];

        if (retVal.isUInt())
        {
            val = retVal.asUInt();
            return true;
        }
    }
    return false;
}

bool ManifestConfigure::Get(const String& key, uint32_t& val)
{
    Value& jval = mImpl->mCfgJson;
    if (jval.isMember(key))
    {
        Value& retVal = jval[key];

        if (retVal.isUInt())
        {
            val = retVal.asUInt();
            return true;
        }
    }
    return false;
}

bool ManifestConfigure::Get(const String& key, uint64_t& val)
{
    Value& jval = mImpl->mCfgJson;
    if (jval.isMember(key))
    {
        Value& retVal = jval[key];

        if (retVal.isUInt64())
        {
            val = retVal.asUInt64();
            return true;
        }
    }
    return false;
}

bool ManifestConfigure::Get(const String& key, float& val)
{
    Value& jval = mImpl->mCfgJson;
    if (jval.isMember(key))
    {
        Value& retVal = jval[key];

        if (retVal.isDouble())
        {
            val = retVal.asFloat();
            return true;
        }
    }
    return false;
}
bool ManifestConfigure::Get(const String& key, double& val)
{
    Value& jval = mImpl->mCfgJson;
    if (jval.isMember(key))
    {
        Value& retVal = jval[key];

        if (retVal.isDouble())
        {
            val = retVal.asDouble();
            return true;
        }
    }
    return false;
}

bool ManifestConfigure::Get(const String& key, Value& val)
{
    Value& jval = mImpl->mCfgJson;
    if (jval.isMember(key))
    {
        val = jval[key];
        return true;
    }
    return false;
}

ManifestConfigure::String  ManifestConfigure::GetOr(const String& key, const String& defVal)
{
    Value& jval = mImpl->mCfgJson;
    if (jval.isMember(key))
    {
        Value& retVal = jval[key];

        if (retVal.isString())
        {
            return retVal.asString();
        }
    }
    return defVal;
}

int8_t  ManifestConfigure::GetOr(const String& key, int8_t defVal)
{
    Value& jval = mImpl->mCfgJson;
    if (jval.isMember(key))
    {
        Value& retVal = jval[key];

        if (retVal.isInt())
        {
            return retVal.asInt();
        }
    }
    return defVal;
}

int16_t ManifestConfigure::GetOr(const String& key, int16_t defVal)
{
    Value& jval = mImpl->mCfgJson;
    if (jval.isMember(key))
    {
        Value& retVal = jval[key];

        if (retVal.isInt())
        {
            return retVal.asInt();
        }
    }
    return defVal;
}

int32_t ManifestConfigure::GetOr(const String& key, int32_t defVal)
{
    Value& jval = mImpl->mCfgJson;
    if (jval.isMember(key))
    {
        Value& retVal = jval[key];

        if (retVal.isInt())
        {
            return retVal.asInt();
        }
    }
    return defVal;
}

int64_t ManifestConfigure::GetOr(const String& key, int64_t defVal)
{
    Value& jval = mImpl->mCfgJson;
    if (jval.isMember(key))
    {
        Value& retVal = jval[key];

        if (retVal.isInt64())
        {
            return retVal.asInt64();
        }
    }
    return defVal;
}

uint8_t ManifestConfigure::GetOr(const String& key, uint8_t defVal)
{
    Value& jval = mImpl->mCfgJson;
    if (jval.isMember(key))
    {
        Value& retVal = jval[key];

        if (retVal.isUInt())
        {
            return retVal.asUInt();
        }
    }
    return defVal;
}

uint16_t ManifestConfigure::GetOr(const String& key, uint16_t defVal)
{
    Value& jval = mImpl->mCfgJson;
    if (jval.isMember(key))
    {
        Value& retVal = jval[key];

        if (retVal.isUInt())
        {
            return retVal.asUInt();
        }
    }
    return defVal;
}

uint32_t ManifestConfigure::GetOr(const String& key, uint32_t defVal)
{
    Value& jval = mImpl->mCfgJson;
    if (jval.isMember(key))
    {
        Value& retVal = jval[key];

        if (retVal.isUInt())
        {
            return retVal.asUInt();
        }
    }
    return defVal;
}

uint64_t ManifestConfigure::GetOr(const String& key, uint64_t defVal)
{
    Value& jval = mImpl->mCfgJson;
    if (jval.isMember(key))
    {
        Value& retVal = jval[key];

        if (retVal.isUInt64())
        {
            return retVal.asUInt64();
        }
    }
    return defVal;
}

float  ManifestConfigure::GetOr(const String& key, float defVal)
{
    Value& jval = mImpl->mCfgJson;
    if (jval.isMember(key))
    {
        Value& retVal = jval[key];

        if (retVal.isDouble())
        {
            return retVal.asFloat();
        }
    }
    return defVal;
}

double ManifestConfigure::GetOr(const String& key, double defVal)
{
    Value& jval = mImpl->mCfgJson;
    if (jval.isMember(key))
    {
        Value& retVal = jval[key];

        if (retVal.isDouble())
        {
            return retVal.asDouble();
        }
    }
    return defVal;
}

Value  ManifestConfigure::GetOr(const String& key, const Value& defVal)
{
    Value& jval = mImpl->mCfgJson;
    if (jval.isMember(key))
    {
        return jval[key];
    }

    return defVal;
}

} /** namespace impl */
} /** namespace ara */
